Skip to content

fix: channels sorting with predefined filters#1747

Merged
isekovanic merged 3 commits into
masterfrom
fix/channels-sorting-with-predefined-filters
May 15, 2026
Merged

fix: channels sorting with predefined filters#1747
isekovanic merged 3 commits into
masterfrom
fix/channels-sorting-with-predefined-filters

Conversation

@isekovanic
Copy link
Copy Markdown
Contributor

CLA

  • I have signed the Stream CLA (required).
  • Code changes are tested

Description of the changes, What, Why and How?

This PR fixes ChannelManager list mutation behavior for queryChannels() calls that use options.predefined_filter.

Previously, predefined filter requests were sent correctly, but queryChannelsRequest() returned only data.channels, so the top level predefined_filter metadata from /channels was discarded. That metadata contains the backend resolved effective filter and sort. Without it, ChannelManager continued using only the original caller inputs for WS-driven list mutations.

For predefined queries, the caller input can be intentionally empty:

filters = {};
sort = [];
options = { predefined_filter: 'messaging_channels' };

while the backend may resolve the actual list semantics to:

  predefined_filter: {
    filter: { archived: false },
    sort: [{ field: 'pinned_at', direction: -1 }],
  }

Because ChannelManager did not have access to that resolved metadata, events such as message.new, notification.message_new, channel.visible and member.updated behaved as if archived and pinned handling was disabled. That could allow archived channels to be promoted into non-archived lists, unarchived channels to be promoted into archived lists or pinned channels to move when pinned_at sorting should keep them stable.

This PR adds an explicit full response query path:

queryChannelsRequestWithResponse()

The existing queryChannelsRequest() keeps its current behavior and still returns only raw channel API responses. queryChannels() also keeps returning Channel[] normally. When called with:

  stateOptions.withResponse = true

queryChannels() returns the full query response with hydrated channels:

  {
    ...queryChannelsResponse,
    channels: Channel[],
  }

ChannelManager then uses this internal withResponse path so it can read response.predefined_filter without changing the default public queryChannels() behaviour.

ChannelManager now keeps the original request inputs separate from the backend resolved response metadata through 2 new state properties:

  • responseFilters
  • responseSort

The original filters, sort and options remain the source of truth for pagination, loadNext(), retries, offline DB query context and preserving the existing pagination state semantics. The new responseFilters and responseSort are used only for local WS driven channel list mutation decisions (i.e when do we promote a channel and how).

The predefined filter response sort shape is:

[{ field: 'pinned_at', direction: -1 }]

but ChannelManager utilities expect ChannelSort:

[{ pinned_at: -1 }]

so we also convert the response sort before storing it as responseSort.

I also considered using the existing channels.queried event to pass this metadata to ChannelManager, however I decided against that for now because channels.queried is client wide and not scoped to a specific ChannelManager request. Without a request/correlation ID, multiple ChannelManagers or direct client.queryChannels() calls could very well race and attach resolved metadata to the wrong list. The metadata is also local list state, not general client state and event ordering would be fragile because ChannelManager updates pagination after its query resolves. The explicit withResponse return path keeps the data tied directly to the request that produced it.

Changelog

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

Size Change: +2.31 kB (+0.6%)

Total Size: 387 kB

📦 View Changed
Filename Size Change
dist/cjs/index.browser.js 129 kB +767 B (+0.6%)
dist/cjs/index.node.js 130 kB +771 B (+0.6%)
dist/esm/index.mjs 128 kB +774 B (+0.61%)

compressed-size-action

@isekovanic isekovanic changed the title Fix/channels sorting with predefined filters fix: channels sorting with predefined filters May 14, 2026
@isekovanic isekovanic merged commit 5ee79f7 into master May 15, 2026
4 checks passed
@isekovanic isekovanic deleted the fix/channels-sorting-with-predefined-filters branch May 15, 2026 08:06
github-actions Bot pushed a commit that referenced this pull request May 15, 2026
## [9.44.2](v9.44.1...v9.44.2) (2026-05-15)

### Bug Fixes

* channels sorting with predefined filters ([#1747](#1747)) ([5ee79f7](5ee79f7))
@stream-ci-bot
Copy link
Copy Markdown

🎉 This PR is included in version 9.44.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants